#include <common.h>
#include <ast/ast.h>
#include <parser/front.h>
#include <dot/astdot.h>
#include <fstream>
#include <analyze_args.h>
#include <ir/visitor.h>
#include <ir/ir.h>
#include <ir/print.h>
#include <riscv/comp_unit.h>
#include <riscv/visitor.h>
#include <riscv/print.h>

int main(int argc, char *argv[]) {
  analyze_args(argc, argv);

  Assert(!source_file_name.empty(), "source_file_name is empty");
  Front front;
  if(front.parse(source_file_name) != 0) {
    std::cerr << "front parse failed" << std::endl;
    return -1;
  }
  std::unique_ptr<ast::NodeCompUnit> comp_unit = std::move(front.result);

  // write dot source to file
  if(!dot_file_name.empty()) {
    std::fstream file;
    file.open(dot_file_name, std::ios::out);
    AstDot ast_dot(file);
    ast_dot.visit(*comp_unit);
    ast_dot.write();
    file.close();
  }

  if((int)stage == DOT) return 0;

  // gen ir
  ir::CompUnit ir_comp_unit;
  ir::Visitor visitor(&ir_comp_unit);
  visitor.visit(*comp_unit);

  // print ir
  if(!ir_file_name.empty()) {
    std::fstream file;
    file.open(ir_file_name, std::ios::out);
    ir::Print ir_print(file);
    ir_print.print(ir_comp_unit);
    file.close();
  }

  if(stage == IR) return 0;

  // gen riscv asm
  riscv::CompUnit riscv_comp_unit;
  riscv::Visitor riscv_visitor(&riscv_comp_unit);
  riscv_visitor.visit(ir_comp_unit);

  // print riscv asm
  if(out_file_name.empty()) {
    out_file_name = "./1.S";
  }
  std::fstream out_file;
  out_file.open(out_file_name, std::ios::out);
  riscv::Print riscv_print(out_file);
  riscv_print.print(riscv_comp_unit);
  out_file.close();

  return 0;
}
